/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package aprendizajePorRefuerzo.entorno;

import aprendizajePorRefuerzo.accion.Accion;
import aprendizajePorRefuerzo.accion.AccionGrilla;
import aprendizajePorRefuerzo.estado.Estado;
import aprendizajePorRefuerzo.estado.EstadoGrilla;
import aprendizajePorRefuerzo.reward.RewardImp;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 *
 * @author Fernando Sorzana
 */
public class EntornoGrilla implements Entorno {
    
    private int cantidadFilas;
    
    private int cantidadColumnas;
    
    private Set<Estado> intransitables;
    
    private Set<Estado> finales;
    
    private Estado inicial;
    
    private RewardImp rewardComun;
    
    private RewardImp rewardFinal;

    public EntornoGrilla(int cantidadFilas, int cantidadColumnas) {
        this.cantidadFilas = cantidadFilas;
        this.cantidadColumnas = cantidadColumnas;
        this.intransitables = new HashSet<>();
        this.finales = new HashSet<>();
        this.rewardComun = new RewardImp(0.0);
        this.rewardFinal = new RewardImp(1.0);
    }

    public int getCantidadFilas() {
        return cantidadFilas;
    }

    public void setCantidadFilas(int cantidadFilas) {
        this.cantidadFilas = cantidadFilas;
    }

    public int getCantidadColumnas() {
        return cantidadColumnas;
    }

    public void setCantidadColumnas(int cantidadColumnas) {
        this.cantidadColumnas = cantidadColumnas;
    }

    public Set<Estado> getIntransitables() {
        return intransitables;
    }

    public void setIntransitables(Set<Estado> intransitables) {
        this.intransitables = intransitables;
    }

    public Set<Estado> getFinales() {
        return finales;
    }

    public void setFinales(Set<Estado> finales) {
        this.finales = finales;
    }

    public RewardImp getRewardComun() {
        return rewardComun;
    }

    public RewardImp getRewardFinal() {
        return rewardFinal;
    }

    @Override
    public RespuestaEntorno devolverRespuesta(Estado estado, Accion accion) {
        if (!EstadoGrilla.class.isAssignableFrom(estado.getClass()) || !AccionGrilla.class.isAssignableFrom(accion.getClass())){
            return null;
        } else {
            int filaNueva = ((EstadoGrilla) estado).getFila() + ((AccionGrilla) accion).getCambioFila();
            if (filaNueva < 0 || filaNueva >= cantidadFilas){
                filaNueva = ((EstadoGrilla) estado).getFila();
            }
            int columnaNueva = ((EstadoGrilla) estado).getColumna() + ((AccionGrilla) accion).getCambioColumna();
            if (columnaNueva < 0 || columnaNueva >= cantidadColumnas){
                columnaNueva = ((EstadoGrilla) estado).getColumna();
            }
            EstadoGrilla estadoNuevo = new EstadoGrilla(false, true, filaNueva, columnaNueva);
            if (intransitables.contains(estadoNuevo)){
                return new RespuestaEntorno(rewardComun,estado);
            }
            if (finales.contains(estadoNuevo)){
                estadoNuevo.setFinal(true);
            }
            RewardImp reward = estadoNuevo.esFinal() ? rewardFinal : rewardComun;
            return new RespuestaEntorno(reward, estadoNuevo);
        }
    }
    
    public void agregarFinal(Estado estado){
        this.finales.add(estado);
    }
    
    public void quitarFinal(Estado estado){
        this.finales.remove(estado);
    }
    
    public void agregarIntransitable(Estado estado){
        this.intransitables.add(estado);
    }
    
    public void quitarIntransitable(Estado estado){
        this.intransitables.remove(estado);
    }
    
    public void agregarInicial(Estado estado){
        this.inicial = estado;
    }
    
    public void quitarInicial(Estado estado){
        this.inicial = null;
    }
    
    public Estado getInicial(){
        return inicial;
    }

    public void setInicial(Estado inicial) {
        this.inicial = inicial;
    }

    @Override
    public List<Estado> getEstados() {
        List<Estado> estados = new ArrayList<Estado>();
        for (int f = 0; f < cantidadFilas; f++){
            for (int c = 0; c < cantidadFilas; c++){
                estados.add(new EstadoGrilla(false,true,f,c));
            }
        }
        return estados;
    }
    
}
